home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpat2-1.000 / xpat2-1 / xpat2-1.04 / src / moves.c < prev    next >
C/C++ Source or Header  |  1995-10-13  |  22KB  |  816 lines

  1. /*****************************************************************************/
  2. /*                                         */
  3. /*                                         */
  4. /*    X patience version 2 -- module moves.c                     */
  5. /*                                         */
  6. /*    General utility functions for all rule sets                 */
  7. /*    written by Heiko Eissfeldt and Michael Bischoff                 */
  8. /*    see COPYRIGHT.xpat2 for Copyright details                 */
  9. /*                                         */
  10. /*                                         */
  11. /*****************************************************************************/
  12. #include "xpatgame.h"
  13.  
  14. #include <time.h>
  15. #include <limits.h>    /* for INT_MAX */
  16. #include <math.h>
  17.  
  18. /* RNG patch: */
  19. int rng = 1;
  20. static int myrand(int limit) {
  21.     /* select one of the RNGs. */
  22.     return rng ?
  23.     (int)(((double)(prand()) / (double)PRANDMAX) * (double)limit)
  24.         : prand() % limit;
  25. }
  26.  
  27. static Move Klondike_deal_cards(void) {
  28.     int rem = CARDS_ON_PILE(IDECK);
  29.     
  30.     if (rem > rules.param[2])
  31.     rem = rules.param[2];
  32.     graphics_pile_control(Disable, IDECK);
  33.     graphics_pile_control(Disable, VDECK);
  34.     if (rem) {
  35.     int i;
  36.     /* without graphics: */
  37.     for (i = 0; i < rem; ++i)
  38.         do_move(INDEX_OF_LAST_CARD(IDECK), VDECK);
  39.     } else {
  40.     while (!EMPTY(VDECK))
  41.         do_move(INDEX_OF_LAST_CARD(VDECK), IDECK);
  42.     ++game.counter[1];
  43.     }
  44.     graphics_pile_control(EnableAndRedraw, IDECK);
  45.     graphics_pile_control(EnableAndRedraw, VDECK);
  46.     return NEW_CARDS_MOVE | MOVE(0, rem);
  47. }
  48.  
  49. static void Klondike_undeal_cards(int num) {
  50.     graphics_pile_control(Disable, IDECK);
  51.     graphics_pile_control(Disable, VDECK);
  52.     if (!num) {
  53.     /* undo flip */
  54.     while (!EMPTY(IDECK))
  55.         do_move(INDEX_OF_LAST_CARD(IDECK), VDECK);
  56.     --game.counter[1];
  57.     } else {
  58.     int i;
  59.     for (i = 0; i < num; ++i)
  60.         do_move(INDEX_OF_LAST_CARD(VDECK), IDECK);
  61.     }
  62.     graphics_pile_control(EnableAndRedraw, IDECK);
  63.     graphics_pile_control(EnableAndRedraw, VDECK);
  64. }
  65.  
  66. Move SlotShuffle(int fwd) {
  67.     int i, tab[MAXCARDS];
  68.     int num = INDEX_OF_FIRST_CARD(LAST_SLOT+1)
  69.     - INDEX_OF_FIRST_CARD(FIRST_SLOT);
  70.     Cardindex start = INDEX_OF_FIRST_CARD(FIRST_SLOT);
  71.  
  72.     sprand(game.seed);
  73.     for (i = 0; i < num; ++i) {
  74.     int j;
  75.     j = myrand(num);
  76.     if (j < i)    /* some correction */
  77.         j = i;
  78.     tab[i] = j;
  79.     }
  80.     if (fwd) {
  81.     for (i = 0; i < num; ++i)
  82.         if (tab[i] != i) {
  83.         /* swap card */
  84.         Card c;
  85.         c = game.cards[start+i];
  86.         game.cards[start+i] = game.cards[start+tab[i]];
  87.         game.cards[start+tab[i]] = c;
  88.         }
  89.     } else {
  90.     for (i = num-1; i >= 0; --i)
  91.         if (tab[i] != i) {
  92.         /* swap card */
  93.         Card c;
  94.         c = game.cards[start+i];
  95.         game.cards[start+i] = game.cards[start+tab[i]];
  96.         game.cards[start+tab[i]] = c;
  97.         }
  98.     }
  99.     for (i = FIRST_SLOT; i <= LAST_SLOT; ++i)
  100.     draw_pileupdate(i, 0);
  101.     return SHUFFLING;
  102. }
  103.  
  104. #ifdef DEBUG
  105. static int type[200];
  106.  
  107. static void count(void) {
  108.     int i;
  109.     memset(type, 0, sizeof(type));
  110.     for (i = 0; i < rules.numcards; ++i)
  111.     ++type[game.cards[i]];
  112.     for (i = 0; i < 52; ++i)
  113.     if (type[i] != rules.numdecks)
  114.         fprintf(stderr, "Card %d: Number = %d\n", i, type[i]);
  115. }
  116. #endif
  117.  
  118. void memo_alloc(int num) {
  119.     game.numalloc = ((num - 1) | 0xf) + 1;    /* multiple of 16 */
  120.     if (!(game.move = malloc(game.numalloc * sizeof(Move)))) {
  121.     fprintf(stderr, "out of memory\n");
  122.     exit(EXIT_FAILURE);
  123.     }
  124. }
  125.  
  126.  
  127. static void makespace(int n) {
  128.     if (game.move_ptr + n > game.numalloc) {
  129.     Move *tmpnew;
  130.     if (!(tmpnew = realloc(game.move, (game.numalloc+256) * sizeof(Move)))) {
  131.         fprintf(stderr, "out of memory. saving game in xpat.tmp\n");
  132.         save_game("xpat.tmp");
  133.         exit(EXIT_FAILURE);
  134.     }
  135.     game.numalloc += 256;
  136.     game.move = tmpnew;
  137.     }
  138. }
  139.  
  140. /* A new move is done. This resets the limit of redo to the current point. */
  141. /* Also, the Bookmark is possibly taken back */
  142. /* if the AUTOFILL_TMPS feature is set, empty tmps are filled from the deck */
  143. void store_move(Move m) {
  144.     makespace(1);
  145.     if (game.bookmark > game.move_ptr)    /* reset Bookmark position */
  146.     game.bookmark = game.move_ptr;
  147.     if ((rules.variant & AUTOFILL_TMPS) && (m & SPECIAL_MOVE) != SPECIAL_MOVE) {
  148.     Pileindex srcpile = DSTPILE(m >> 16);
  149.     if (game.piletype[srcpile] == Tmp && (!EMPTY(IDECK) || !EMPTY(VDECK))) {
  150.         /* this is the case we have to deal with */
  151.         makespace(3);
  152.         game.move[game.move_ptr++] = COMPOUND_BEGIN;
  153.         game.move[game.move_ptr++] = m;
  154.         game.move[game.move_ptr++] = !EMPTY(VDECK) ?
  155.         do_move(INDEX_OF_LAST_CARD(VDECK), srcpile) :
  156.         do_move(INDEX_OF_LAST_CARD(IDECK), srcpile);
  157.         m = COMPOUND_END;
  158.     }
  159.     }
  160.     game.move[game.move_ptr] = m;
  161.     game.stored_moves = ++game.move_ptr;
  162.     ++game.n_moves;
  163.  
  164.     /* now that the work is done, check for finished game */
  165.     check_win_game();
  166. }
  167.  
  168. static void undo_give_cards(int num) {
  169.     /* num = number of cards */
  170.     /* printf("undo give %d cards\n", num); */
  171.     if (rules.undeal_cards)
  172.     (*rules.undeal_cards)(num);
  173.     else if (rules.variant & KLONDIKE_DEAL)
  174.     Klondike_undeal_cards(num);
  175.     else {
  176.     int i;
  177.     graphics_pile_control(Disable, IDECK);
  178.     for (i = FIRST_SLOT + num; i != FIRST_SLOT; --i)
  179.         /* slot i-1 back to deck */
  180.         do_move(game.ind[i]-1, IDECK);
  181.     graphics_pile_control(EnableAndRedraw, IDECK);
  182.     }
  183. }
  184.  
  185.  
  186. int undo_move(void) {
  187.     Move m;
  188.     int retval = 1;    /* no cheat */
  189.  
  190.     if (!game.move_ptr) {
  191.     /* possibly undo restart game? */
  192.     if (game.stored_moves) {
  193.         jumpto_movenr(game.stored_moves);    /* must replay the game */
  194.         return 1;
  195.     }
  196.     return 0;
  197.     }
  198.     m = game.move[--game.move_ptr];
  199.     --game.n_moves;
  200.     if ((m & SPECIAL_MOVE) == SPECIAL_MOVE) {
  201.     switch (m & SPECIAL_MASK) {
  202.     case COMPOUND_END:
  203.         {
  204.         int remember_count, remgraphic;
  205.         if ((remgraphic = game.graphic))
  206.             graphics_control(Disable);
  207.         /* undo multiple moves */
  208.         remember_count = game.n_moves;
  209.         while (game.move[game.move_ptr-1] != COMPOUND_BEGIN) {
  210.             if (undo_move() == 2)
  211.             retval = 2;
  212.         }
  213.         --game.move_ptr;
  214.         game.n_moves = remember_count;
  215.         if (remgraphic)
  216.             graphics_control(EnableAndRedraw);
  217.         }
  218.         return retval;    
  219.     case ADD_CHEAT:
  220.         game.cheat_count += (int)(m & SPECIAL_ARGS);
  221.         return 2;
  222.     case NEW_CARDS_MOVE:
  223.         undo_give_cards(DSTPILE(m));
  224.         if (DSTPILE(m)) {
  225.         game.cheat_count += DSTPILE(m);
  226.         return 2;
  227.         }
  228.         return 1;
  229.     case ROTATE_UP:
  230.         /* change counter */
  231.         {   int c;
  232.         for (c = 0; c < 4; ++c)
  233.             if (rules.paramstring[c] == TXTI_ROTATE)
  234.             game.counter[c] -= 2;
  235.         }
  236.         RotateDown(SRCIND(m));
  237.         return 1;
  238.     case ROTATE_DOWN:
  239.         /* change counter */
  240.         {   int c;
  241.         for (c = 0; c < 4; ++c)
  242.             if (rules.paramstring[c] == TXTI_ROTATE)
  243.             game.counter[c] -= 2;
  244.         }
  245.         RotateUp(SRCIND(m));
  246.         return 1;
  247.     case SHUFFLING:
  248.         SlotShuffle(0);
  249.         return 1;
  250.     default:
  251.         /* printf("Move in error is %08lx\n", m); */
  252.         assert(0);
  253.     }
  254.     return 0;
  255.     }
  256.     /* standard move follows */
  257.     if (m & MOVE_TURNED) {
  258.     m >>= 16;    /* upper part = undo information */
  259.     ++game.cheat_count;
  260.     game.visible[game.ind[DSTPILE(m)+1]-1] = 0;    /* invisible again! */
  261.     retval = 2;
  262.     } else
  263.         m >>= 16;    /* upper part = undo information */
  264.  
  265.     (void)do_move(SRCIND(m), DSTPILE(m));
  266.     if (retval == 2)
  267.     draw_pileupdate(DSTPILE(m), 0);            /* hide card again! */
  268.     return retval;
  269. }
  270.  
  271. int redo_move(void) {
  272.     Move m;
  273.     int retval = 1;
  274.     if (game.move_ptr == game.stored_moves)
  275.     return 0;    /* no redo possible */
  276.     m = game.move[game.move_ptr++];
  277.     ++game.n_moves;
  278.     if ((m & SPECIAL_MOVE) == SPECIAL_MOVE) {
  279.     switch (m & SPECIAL_MASK) {
  280.     case COMPOUND_BEGIN:
  281.         {
  282.         int remember_count, remgraphic;
  283.         if ((remgraphic = game.graphic))
  284.             graphics_control(Disable);
  285.         /* redo multiple moves */
  286.         remember_count = game.n_moves;
  287.         while (game.move[game.move_ptr] != COMPOUND_END) {
  288.             if (redo_move() == 2)
  289.             retval = 2;
  290.         }
  291.         ++game.move_ptr;
  292.         game.n_moves = remember_count;
  293.         if (remgraphic)
  294.             graphics_control(EnableAndRedraw);
  295.         }
  296.         return retval;
  297.     case ADD_CHEAT:
  298.         game.cheat_count -= (int)(m & SPECIAL_ARGS);
  299.         return 2;
  300.     case ROTATE_UP:
  301.         RotateUp(SRCIND(m));
  302.         return 1;
  303.     case ROTATE_DOWN:
  304.         RotateDown(SRCIND(m));
  305.         return 1;
  306.     case NEW_CARDS_MOVE:
  307.         retval = DSTPILE(give_new_cards());
  308.         if (retval) {
  309.         game.cheat_count -= retval;
  310.         return 2;
  311.         }
  312.         return 1;
  313.     case SHUFFLING:
  314.         SlotShuffle(1);
  315.         return 1;
  316.     default:
  317.         assert(0);
  318.     }
  319.     }
  320.     if (m & MOVE_TURNED) {
  321.     --game.cheat_count;
  322.     retval = 2;
  323.     }
  324.     (void)do_move(SRCIND(m), DSTPILE(m));
  325.     return retval;
  326. }
  327.  
  328.  
  329. static void shuffle(void) {
  330.     int i, d, v, c;
  331.     int tmp[MAXCARDS];
  332.  
  333.     if (game.graphic)
  334.     show_message(" ");
  335.     i = 0;
  336.     for (d = 0; d < rules.numdecks; ++d)
  337.     for (v = 0; v < rules.cards_per_color; ++v)
  338.         for (c = 0; c < 4; ++c)
  339.         tmp[i++] = c + (v << 2);
  340.     assert(i <= rules.numcards);
  341.     c = 0;
  342.     while (i < rules.numcards)
  343.     tmp[i++] = JOKER + c++;
  344.     while (c < rules.numjokers)
  345.     tmp[myrand(rules.numcards)] = JOKER + c++;    /* subst old cards */
  346.  
  347.     for (i = rules.numcards; i; --i) {
  348.     v = myrand(i);
  349.     /* printf("rand() = %d\n", v); */
  350.     /* look for the vth non-empty card in tmp */
  351.     c = -1;
  352.     do {
  353.         while (tmp[++c] == -1)
  354.         ;            /* skip card */
  355.     } while (v--);
  356.     game.cards[i-1] = tmp[c];
  357.     /* printf("c = %d, card = %d\n", c, game.cards[i-1]); */
  358.     tmp[c] = -1;
  359.     }
  360. }
  361.  
  362. Pileindex getpile(Cardindex ind) {
  363.     int i;
  364.     assert(ind < rules.numcards);
  365.     i = 0;
  366.     while (ind >= game.ind[i+1])
  367.     ++i;
  368.     return i;
  369. }
  370.  
  371. /* These are the central card moving routines, i.e. the only functions which */
  372. /* change the contents of the game.cards array within a game.             */
  373. /* Every time anything is changed, one of these functions is called.           */
  374. /* We can reset hint tables at this point.                      */
  375.  
  376. Move RotateUp(Cardindex src) {
  377.     Pileindex p = getpile(src);
  378.     int c;
  379.     Cardindex i;
  380.  
  381.     cmd_CancelSelection();
  382.     i = INDEX_OF_LAST_CARD(p);
  383.     c = game.cards[i];
  384.     while (--i >= src)
  385.     game.cards[i+1] = game.cards[i];
  386.     game.cards[i+1] = c;
  387.     draw_pileupdate(p, 0);
  388.     /* change counter */
  389.     for (c = 0; c < 4; ++c)
  390.     if (rules.paramstring[c] == TXTI_ROTATE)
  391.         ++game.counter[c];
  392.     return ROTATE_UP | MOVE(src, 0);
  393. }
  394. Move RotateDown(Cardindex src) {
  395.     Pileindex p = getpile(src);
  396.     int c;
  397.     Cardindex i;
  398.  
  399.     cmd_CancelSelection();
  400.     c = game.cards[src];
  401.     for (i = src; i < INDEX_OF_LAST_CARD(p); ++i)
  402.     game.cards[i] = game.cards[i+1];
  403.     game.cards[i] = c;
  404.     draw_pileupdate(p, 0);
  405.     /* change counter */
  406.     for (c = 0; c < 4; ++c)
  407.     if (rules.paramstring[c] == TXTI_ROTATE)
  408.         ++game.counter[c];
  409.     return ROTATE_DOWN | MOVE(src, 0);
  410. }
  411. Move do_move(Cardindex srcindex, Pileindex dstpile) {
  412.     int srcpile, numcards;
  413.     int tmp[MAXCARDS];
  414.     int vis;
  415.     Move m;
  416.  
  417.     cmd_CancelSelection();    /* calls cmd_ResetHints() */
  418.     if (srcindex == -1)
  419.     return NO_MOVE;
  420.  
  421.     srcpile = getpile(srcindex);
  422.     numcards = game.ind[srcpile+1] - srcindex;
  423.     m = MOVE(srcindex, dstpile);
  424.     if (srcindex > game.ind[srcpile] && !game.visible[srcindex-1] &&
  425.     (srcpile != IDECK || rules.variant & DECK_VISIBLE)) {
  426.     game.visible[srcindex-1] = 1;
  427.     m |= MOVE_TURNED;
  428.     }
  429.  
  430.     memcpy(tmp, game.cards+srcindex, numcards * sizeof(int));
  431.     /* moved cards are normally visible */
  432.     vis = dstpile != IDECK || rules.variant & DECK_VISIBLE;
  433.     /* printf("move %d to %d, %d cards\n", srcindex, dstpile, numcards); */
  434.     assert(srcpile != dstpile);
  435.     if (srcpile < dstpile) {
  436.     /* ldir */
  437.     int i;
  438.     m |= MOVE(game.ind[dstpile+1]-numcards, srcpile) << 16;
  439.     for (i = srcindex; i < game.ind[dstpile+1]-numcards; ++i)
  440.         move_card_data(i, i+numcards);
  441.     memcpy(game.cards+i, tmp, numcards * sizeof(int));
  442.     for (; i < game.ind[dstpile+1]; ++i)
  443.         game.visible[i] = vis;
  444.     for (i = srcpile + 1; i <= dstpile; ++i)
  445.         game.ind[i] -= numcards;
  446.     } else {
  447.     /* lddr ; shift a block backwards; begin at the tail */
  448.     int i;
  449.     m |= MOVE(game.ind[dstpile+1], srcpile) << 16;
  450.     for (i = srcindex - 1; i >= game.ind[dstpile+1]; --i)
  451.         move_card_data(i+numcards, i);
  452.     memcpy(game.cards + game.ind[dstpile+1], tmp, numcards * sizeof(int));
  453.     for (i = 0; i < numcards; ++i)
  454.         game.visible[game.ind[dstpile+1] + i] = vis;
  455.     for (i = dstpile+1; i <= srcpile; ++i)
  456.         game.ind[i] += numcards;
  457.     }
  458. #ifdef DEBUG
  459.     count();
  460. #endif
  461.     /* inform graphics interface of change */
  462.     draw_pileupdate(srcpile, -numcards);
  463.     draw_pileupdate(dstpile, numcards);
  464.     /* printf("Move done is %08lx\n", m); */
  465.     return m;
  466. }
  467.  
  468.  
  469. int all_to_stack(void) {
  470.     int i, flag, anymove;
  471.  
  472.     anymove = 0;
  473.     do {
  474.     flag = 0;
  475.     for (i = 0; i < game.numpiles; ++i) {
  476.         switch (game.piletype[i]) {
  477.         case Slot:
  478.         case Tmp:
  479.         case FaceupDeck:
  480.         if (move_to_stack(i)) {
  481.             flag = 1;
  482.             anymove = 1;
  483.         }
  484.         break;
  485.         default:
  486.         ;
  487.         }
  488.     }
  489.     } while (flag);
  490.     return anymove;
  491. }
  492.  
  493. static void init_seed(long seed) {
  494.     if (seed < 0) {
  495.     game.seed = -1L;    /* to guarantee a mismatch later */
  496.     seed = (long)time(NULL);
  497.     }
  498.     seed %= PRANDMAX;
  499.     if (seed < 0L)
  500.     seed += PRANDMAX;    /* I think this shouldn't happen */
  501.     if (seed == game.seed) {    /* restart game */
  502.     /* stored_moves stays valid */
  503.     game.cheat_count += 1000;
  504.     } else {
  505.     game.seed = seed;
  506.     game.cheat_count = game.stored_moves = 0;
  507.     game.finished = False;    /* this is really a new game */
  508.     }
  509.     game.n_moves = 0;
  510.     game.move_ptr = 0;
  511.     game.counter[0] = 0;
  512.     game.counter[1] = 0;
  513.     game.counter[2] = 0;
  514.     game.counter[3] = 0;
  515.     sprand(seed);
  516. }
  517.  
  518. static void distribute(char *xx, int rest, int piles)
  519. {   int i, k, invert = 0;
  520.  
  521.     if (!piles)
  522.     return;
  523.     if (2 * rest > piles+1) {
  524.     rest = piles - rest;
  525.     invert = 1;
  526.     }
  527.     memset(xx, invert, piles);
  528.     if (rest) {
  529.     k = (piles-1) / rest + 1;    /* ceil(slots/rest) */
  530.     for (i = 0; i < piles; i += k) {
  531.         xx[i] = 1-invert;
  532.         if (!--rest)
  533.         break;
  534.     }
  535.     /* the rest is distributed quite ugly */
  536.     for (i = 0; rest; ++i)
  537.         if (xx[i] == invert) {
  538.         xx[i] = 1-invert;
  539.         --rest;
  540.         }
  541.     }
  542. }
  543.  
  544. static void gen_newgame(void)
  545. {   int i, rest;
  546.     char xx[MAXPILES];
  547.  
  548.     memset(xx, 0, MAXPILES);
  549.     if (rules.facedown && !rules.faceup) {
  550.     fprintf(stderr, "newgame(): topmost card must be face-up, correcting it\n");
  551.     --rules.facedown;
  552.     ++rules.faceup;
  553.     }
  554.     if (rules.newgame_bits & SLOTS_SAME)
  555.     rest = 0;
  556.     else
  557.     rest = rules.numcards % rules.numslots;    /* cards that are too much */
  558.  
  559.     if (rules.numcards < rest + rules.numslots * (rules.faceup + rules.facedown)) {
  560.     fprintf(stderr, "newgame(): too many cards specified, resetting to min values\n");
  561.     rules.faceup = 1;
  562.     rules.facedown = 0;
  563.     }
  564.  
  565.     /* generate nice distribution of rest cards */
  566.     if (rest > rules.numtmps || (rules.newgame_bits & FORCE_SLOTS))
  567.      /* distribute on slots */
  568.     distribute(xx+FIRST_SLOT, rest, rules.numslots);
  569.     else
  570.     /* distribute on tmps */
  571.     distribute(xx+LAST_SLOT+1, rest, rules.numtmps);
  572.  
  573.     for (i = 0; i <= FIRST_SLOT; ++i)
  574.     game.ind[i] = 0;
  575.     for (i = FIRST_SLOT; i <= LAST_SLOT; ++i) {
  576.     int j;
  577.     game.ind[i+1] = game.ind[i] + rules.facedown + rules.faceup + xx[i];
  578.     for (j = game.ind[i+1] - rules.faceup; j < game.ind[i+1]; ++j)
  579.         game.visible[j] = 1;        /* card is turned */
  580.     }
  581.     while (++i < game.numpiles)
  582.     game.ind[i] = game.ind[i-1] + xx[i-1];
  583.     /* all cards on the tmps are faceup */
  584.     for (i = game.ind[LAST_SLOT+1]; i < game.ind[IDECK]; ++i)
  585.     game.visible[i] = 1;
  586.     if (rules.variant & DECK_VISIBLE)
  587.     game.visible[rules.numcards-1] = 1;    /* topmost card on deck */
  588.     if (!rules.facedown)
  589.     for (i = game.ind[FIRST_SLOT]; i < game.ind[LAST_SLOT+1]; ++i)
  590.          game.visible[i] = 1;    /* all cards on the slots visible */
  591. }
  592.  
  593.  
  594. static void MO_newgame(void) {
  595.     int i, remcards = rules.numcards;
  596.     /* specific part: */
  597.     for (i = 0; i < rules.numslots; ++i) {
  598.     int here;
  599.     here = min(remcards, rules.faceup + rules.facedown);
  600.     remcards -= here;
  601.     game.ind[rules.numstacks+i+1] = game.ind[rules.numstacks+i] + here;
  602.     if (here) {
  603.         Cardindex j;
  604.         j = game.ind[rules.numstacks+i+1] - 1;
  605.         do
  606.         game.visible[j--] = 1;
  607.         while (j >= game.ind[rules.numstacks+i] + rules.facedown);
  608.     }
  609.     }
  610. }
  611.  
  612. void newgame(long seed) {
  613.     int i;
  614.  
  615.     game.randomgame = (seed == -1L);
  616.     game.savecount = 0;
  617.     game.bookmark = 0;
  618.     init_seed(seed);
  619.     shuffle();    /* initialize game.cards */
  620.  
  621.     for (i = 0; i < rules.numcards; ++i)
  622.     game.visible[i] = 0;
  623.     for (i = 0; i < game.numpiles; ++i)
  624.     game.ind[i] = 0;    /* no cards on the piles */
  625.     game.ind[i] = rules.numcards;    /* rest on the deck */
  626.  
  627.     if (rules.new_game)
  628.     (*rules.new_game)();
  629.     else if (rules.newgame_bits & SEQUENTIAL)
  630.     MO_newgame();
  631.     else
  632.     gen_newgame();
  633.  
  634.     if (game.graphic)
  635.     for (i = 0; i < game.numpiles; ++i)
  636.         pile_resize(i);
  637.     /* (void)do_move(-1, -1); */        /* reset game.*/
  638.     cmd_ResetHints();
  639.     game.srcind = UNSELECTED;
  640. }
  641.  
  642. /* generic give-cards routine */
  643.  
  644. Move give_new_cards(void) {
  645.     if (rules.deal_cards)
  646.     return (*rules.deal_cards)();
  647.     else if (rules.variant & KLONDIKE_DEAL)
  648.     return Klondike_deal_cards();
  649.     else {
  650.     int i, rem;
  651.     
  652.     graphics_pile_control(Disable, IDECK);
  653.     rem = CARDS_ON_PILE(IDECK);
  654.     if (rem > rules.numslots)
  655.         rem = rules.numslots;
  656.     for (i = 0; i < rem; ++i)
  657.         do_move(INDEX_OF_LAST_CARD(IDECK), rules.numstacks + i);
  658.     graphics_pile_control(EnableAndRedraw, IDECK);
  659.     return NEW_CARDS_MOVE | MOVE(0, rem);
  660.     }
  661. }
  662.  
  663.  
  664.  
  665.  
  666.  
  667. extern struct rules Spider_rules, Gypsy_rules, Klondike_rules, modSpider_rules;
  668. extern struct rules Seahaven_rules, FreeCell_rules, IdiotsDelight_rules,
  669.     MonteCarlo_rules, MidnightOil_rules, Calculation_rules, Michaels_rules,
  670.     Canfield_rules, modCanfield_rules, Royal_rules, Bakers_rules;
  671.  
  672. struct game game;
  673. struct rules rules;
  674.  
  675. struct rules *rulepool[] = {
  676.     &Spider_rules,
  677.     &Gypsy_rules,
  678.     &Klondike_rules,
  679.     &Seahaven_rules,
  680.     &FreeCell_rules,
  681.     &IdiotsDelight_rules,
  682.     &MonteCarlo_rules,
  683.     &MidnightOil_rules,
  684.     &Calculation_rules,
  685.     &modCanfield_rules,
  686.     &Michaels_rules,
  687.     &Canfield_rules,
  688.     &Royal_rules,
  689.     &Bakers_rules,
  690.     NULL
  691. };
  692.  
  693. struct rules *getrules(const char *ruleset) {
  694.     int i;
  695.     for (i = 0; rulepool[i]; ++i)
  696.     if (!strcmp(ruleset, rulepool[i]->shortname) ||
  697.         (rulepool[i]->abbrev && !strcmp(ruleset, rulepool[i]->abbrev))) {
  698.         return rulepool[i];
  699.     }
  700.     return NULL;
  701. }
  702.  
  703. void new_rules(const char *ruleset, int decks, int slots, int faceup, int facedown,
  704.     int jokers, int tmps, int param0, int param1, int param2, int param3) {
  705.     int i;
  706.     struct rules *rp;
  707.     if (!game.numalloc)
  708.     memo_alloc(512);
  709.     game.seed = -1L;        /* no replay is valid */
  710.                 /* that will set finished to False */
  711.  
  712.     if (!(rp = getrules(ruleset))) {
  713.     fprintf(stderr, "Unknown rule set. Known rules are:\n");
  714.     for (i = 0; rulepool[i]; ++i) {
  715.         char buff[20];
  716.         if (rulepool[i]->abbrev)
  717.         sprintf(buff, "(Abbrev %-2s)", rulepool[i]->abbrev);
  718.         else
  719.         strcpy(buff, "           ");
  720.         fprintf(stderr, "%-15s %s -- %s\n", rulepool[i]->shortname, buff,
  721.             rulepool[i]->longname ? rulepool[i]->longname : "");
  722.     }
  723.     exit(EXIT_FAILURE);
  724.     }
  725.     rules = *rp;    /* copy std game.*/
  726.  
  727.     /* rule customization: */
  728.     if (!(rules.customizable & CUSTOM_DECKS )) decks = -1;
  729.     if (!(rules.customizable & CUSTOM_SLOTS )) slots = -1;
  730.     if (!(rules.customizable & CUSTOM_JOKERS)) jokers = -1;
  731.     if (!(rules.customizable & CUSTOM_TMPS  )) tmps = -1;
  732.     if (!(rules.customizable & CUSTOM_FACEUP)) faceup = -1;
  733.     if (!(rules.customizable & CUSTOM_FACEDOWN)) facedown = -1;
  734.     if (!(rules.customizable & CUSTOM_PARAM0)) param0 = -1;
  735.     if (!(rules.customizable & CUSTOM_PARAM1)) param1 = -1;
  736.     if (!(rules.customizable & CUSTOM_PARAM2)) param2 = -1;
  737.     if (!(rules.customizable & CUSTOM_PARAM3)) param3 = -1;
  738.  
  739.     if (jokers >= 0 && jokers != rules.numjokers) {
  740.     rules.numjokers = jokers;
  741.     rules.customized |= CUSTOM_JOKERS;
  742.     rules.maxscore = 0;    /* custom: maxscore unknown */
  743.     }
  744.     if (param0 >= 0 && param0 != rules.param[0]) {
  745.     rules.param[0] = param0;
  746.     rules.customized |= CUSTOM_PARAM0;
  747.     rules.maxscore = 0;    /* custom: maxscore unknown */
  748.     }
  749.     if (param1 >= 0 && param1 != rules.param[1]) {
  750.     rules.param[1] = param1;
  751.     rules.customized |= CUSTOM_PARAM1;
  752.     rules.maxscore = 0;    /* custom: maxscore unknown */
  753.     }
  754.     if (param2 > 0 && param2 != rules.param[2]) {
  755.     rules.param[2] = param2;
  756.     rules.customized |= CUSTOM_PARAM2;
  757.     rules.maxscore = 0;    /* custom: maxscore unknown */
  758.     }
  759.     if (param3 >= 0 && param3 != rules.param[3]) {
  760.     rules.param[3] = param3;
  761.     rules.customized |= CUSTOM_PARAM3;
  762.     }
  763.     if (faceup >= 0 && faceup != rules.faceup) {
  764.     rules.faceup = faceup;
  765.     rules.customized |= CUSTOM_FACEUP;
  766.     rules.maxscore = 0;    /* custom: maxscore unknown */
  767.     }
  768.     if (facedown >= 0 && facedown != rules.facedown) {
  769.     rules.facedown = facedown;
  770.     rules.customized |= CUSTOM_FACEDOWN;
  771.     rules.maxscore = 0;    /* custom: maxscore unknown */
  772.     }
  773.     if (slots > 0 && slots != rules.numslots) {
  774.     rules.numslots = slots;
  775.     rules.customized |= CUSTOM_SLOTS;
  776.     rules.maxscore = 0;    /* custom: maxscore unknown */
  777.     }
  778.     if (decks > 0 && decks != rules.numdecks) {
  779.     rules.numdecks = decks;
  780.     rules.customized |= CUSTOM_DECKS;
  781.     rules.maxscore = 0;    /* custom: maxscore unknown */
  782.     }
  783.     if (tmps >= 0 && tmps != rules.numtmps) {
  784.     rules.numtmps = tmps;
  785.     rules.customized |= CUSTOM_TMPS;
  786.     }
  787.  
  788.     if (rules.numstacks >= 4)
  789.     rules.numstacks = rules.numdecks * 4;
  790.     rules.numcards = rules.cards_per_color * 4 * rules.numdecks + rules.numjokers;
  791.     if (rules.numcards > MAXCARDS) {
  792.     fprintf(stderr, "new_rules(): parameters give too many cards\n");
  793.     exit(EXIT_FAILURE);
  794.     }
  795.     if (rules.numslots + rules.numstacks + 1 > MAXPILES) {
  796.     fprintf(stderr, "new_rules(): parameters give too many slots\n");
  797.     exit(EXIT_FAILURE);
  798.     }
  799.     for (i = 0; i < rules.numstacks; ++i)
  800.     game.piletype[i] = Stack;
  801.     for (; i < rules.numstacks + rules.numslots; ++i)
  802.     game.piletype[i] = Slot;
  803.     for (; i < rules.numstacks + rules.numslots + rules.numtmps; ++i)
  804.     game.piletype[i] = Tmp;
  805.     if (rules.variant & DECK_SOURCE)
  806.     game.piletype[i++] = FaceupDeck;
  807.     game.piletype[i++] = FacedownDeck;
  808.     game.numpiles = i;
  809.     for (i = 0; i <= game.numpiles; ++i)/* this fixes coredump-bug */
  810.     game.ind[i] = 0;        /* no card currently there */
  811.  
  812.     if (rules.initfunc)            /* initrules-hook */
  813.     (*rules.initfunc)();
  814.     rp->inited = 1;
  815. }
  816.